define(function (require, exports, module) {
    "use strict";
    require('jquery-ui');
    var loading = require('core/tips/loading');
    var notice = require('core/tips/notice');

    var Init = require('init');

    var Table = function (obj) {
        this.obj = obj;
        this.id = obj.attr('id');
        this.initConfig();
        this.initCss();
        this.initAction();
    };

    module.exports = Table;

    Table.prototype.config = {};
    Table.prototype.configModel = {
        url: '',
        headerUrl: '', // 获取表头的URL,
        isObj: false, // 是单个数据结构
        button: {
            refresh: '<span class="fa fa-refresh"></span> 刷新'
            // download: '<span class="fa fa-download"></span> 下载'
        },
        maxRow: 0, // 如果超过这个数字的行就隐藏
        merger: false, // 合并临近单元格
        pageNum: 0, // 大于0表示分页
        noError: false, //不显示错误提示
        sortable: false,
        sortUpdateUrl: '',
        autoFresh: 0
    };

    Table.prototype.initConfig = function () {
        this.config[this.id] = JSON.parse(JSON.stringify(this.configModel));
        for (var i in this.config[this.id]) {
            if (this.obj.attr('data-' + i)) {
                this.config[this.id][i] = this.obj.attr('data-' + i);
            }
        }
    };

    Table.prototype.init = function () {
        var _this = this, sortable = this.config[this.id].sortable;
        this.obj.css('position', 'relative');
        this.initContainer('thead', function (head) {
            head.addClass('bg-light');
            _this.loadHeader(head);
        });
        this.initContainer('tbody', function (body) {
            if (!body.html()) {
                body.html('<tr><td><div style="height:40px"></div></td></tr>');
            }
            if (sortable) {
                var fixHelper = function (e, ui) {
                    ui.children().each(function () {
                        $(this).width($(this).width());
                    });
                    return ui;
                };
                body.sortable({axis: "y", helper: fixHelper, delay: 100});
            }
        });
        this.initContainer('tfoot');
        this.initTableButton();

        this.loadData(this.obj, 1);
        this.autoFresh(this.config[this.id].autoFresh, this.obj);
    };

    Table.prototype.autoFresh = function (autoFresh, obj) {
        if (autoFresh <= 0) {
            return false;
        }
        var _this = this;
        setTimeout(function () {
            _this.loadData(obj, 1);
            _this.autoFresh(autoFresh, obj);
        }, autoFresh * 1000);
    };

    Table.prototype.initContainer = function (tagName, callback) {
        if (this.obj.find(tagName).length) {
            return false;
        }
        this.obj.append('<' + tagName + '></' + tagName + '>');
        if (typeof callback !== 'undefined') {
            callback(this.obj.find('' + tagName + ':last'));
        }
    };

    Table.prototype.initTableButton = function () {
        if (this.obj.children('.tableButton').length > 0) {
            return false;
        }
        this.obj.append('<div class="btn-group tableButton"></div>');
        var btnObj = this.obj.children('.tableButton');
        $.each(this.config[this.id].button, function (key, name) {
            btnObj.append('<button type="button" class="btn btn-xs btn-default" data-tableAction="' + key + '">' + name + '</button>');
        });
    };

    Table.prototype.initAction = function () {
        var _this = this, obj = this.obj, objId = this.id;
        this.obj.on('click', 'button[data-tableAction]', function () {
            switch ($(this).attr('data-tableAction')) {
                case 'refresh':
                    var page = _this.obj.find('.page button:active').text();
                    if (!page || isNaN(page)) {
                        page = 1;
                    }
                    _this.loadData(obj, page);
                    break;
            }
        }).on('click', 'a[data-action]', function () {
            if ($(this).attr('data-confirm') && !confirm($(this).attr('data-confirm'))) {
                return false;
            }
            var action = $(this).attr('data-action'), obj = $(this);
            _this.actionRun($(this).attr('href'), function () {
                switch (action) {
                    case "delete":
                        obj.closest('tr').remove();
                        break;
                }
            });
            return false;
        }).on('click', '._table-plus', function () {
            var tr = $(this).closest('tr'), table = tr.closest('table');
            var fatherId = $(this).attr('data-fid');
            $(this).removeClass('fa-plus-square-o _table-plus').addClass('fa-minus-square-o _table-minus');
            if (tr.next('tr[data-father="' + tr.attr('data-row') + '"]').length <= 0) {
                tr.after('<tr class="no-data"><td colspan="' + table.find('thead tr:last th').length + '"></td></tr>');
                var loadingId = loading.on(tr.next('.no-data'));
                _this.subLoad(table, fatherId, 1, function () {
                    loading.off(loadingId);
                    tr.next('.no-data').remove();
                });
            } else {
                tr.next('tr[data-father="' + tr.attr('data-row') + '"]').show();
            }
            _this.history(tr.attr('data-row'));
        }).on('click', '._table-minus', function () {
            var tr = $(this).closest('tr');
            $(this).removeClass('fa-minus-square-o _table-minus').addClass('fa-plus-square-o _table-plus');
            tr.next('tr[data-father="' + tr.attr('data-row') + '"]').hide();
            _this.history(tr.attr('data-father'));
        }).on('click', 'tr.moreRow', function () {
            var tbody = $(this).closest('tbody');
            tbody.children('tr:hidden').show();
            $(this).remove();
        }).on('sortupdate', function () {
            var sortIds = [], tbody = $(this), table = $(this).parents('[data-fn*="data-table"]').first(),
                tableId = table.attr('id');
            if (!_this.config[tableId] || !_this.config[tableId].sortable || !_this.config[tableId].sortUpdateUrl) {
                return true;
            }
            tbody.children('tr[data-sortId]').each(function () {
                sortIds.push($(this).attr('data-sortId'));
            });
            $.getJSON(_this.config[tableId].sortUpdateUrl + '&ids=' + sortIds.join(',') + '&jsoncallback=?', function (rs) {
                if (rs && rs.status) {
                    for (var i in sortIds) {
                        tbody.children('tr[data-sortId="' + sortIds[i] + '"]').find('input.orderBy').val(parseInt(i) + 1);
                    }
                }
            });
        }).on('click', 'tfoot #tablePage .pagination li a', function () {
            var obj = $(this).parents('table').first();
            if (!$(this).parent().hasClass('active')) {
                var page = parseInt($(this).text());
                _this.selectPage(obj, page);
                localStorage['page_' + window.location.pathname + '_' + obj.attr('id')] = page;
            }
            return false;
        }).on('click', 'thead tr th.sort', function () {
            var next = '+', nextClass = 'sort-up', nowClass = '';
            if ($(this).hasClass('sort-up')) {
                next = '-';
                nextClass = 'sort-down';
                nowClass = 'sort-up';
            } else if ($(this).hasClass('sort-down')) {
                next = '';
                nextClass = '';
                nowClass = 'sort-down';
            }
            nowClass && $(this).removeClass(nowClass);
            nextClass && $(this).addClass(nextClass);

            if (checkSortLocal()){
                _this.loadData(obj,1);
            }else{
                _this.sortData(obj);
            }

            function checkSortLocal() {
                if (obj.find('tfoot #tablePage .pagination li a').length<=0){
                    return false;
                }
                obj.find('tfoot #tablePage .pagination li a').each(function () {
                    if (!isNaN($(this.text())) && obj.find('tbody tr[data-page="'+$(this).text()+'"]').length<=0){
                        return true;
                    }
                });
                return false;
            }
        });

        var relay = this.getRelay(this.config[this.id].url);
        for (var i in relay) {
            $('body').on('change', 'input[name="' + relay[i] + '"],select[name="' + relay[i] + '"]', function () {
                setTimeout(function () {
                    _this.loadData(obj, 1);
                }, 300);
            });
        }
    };

    Table.prototype.subLoad = function (obj, fatherId, page, loadEndCallback) {
        var url = this.readyUrl(obj.attr('id'), fatherId, page), _this = this, noError = this.config[this.id].noError;
        $.getJSON(url, function (rs) {
            loadEndCallback();
            if (rs.status) {
                if (rs.data.length <= 0) {
                    if (!noError) {
                        notice.on('没有数据', 'warning', {icon: true});
                    }
                } else {
                    var tr = obj.find('tbody tr span[data-fid="' + fatherId + '"]').closest('tr');
                    $.each(rs.data, function (dataI, data) {
                        _this.putRow(tr, tr.attr('data-row') + '~' + page + '-' + dataI, data, obj.children('thead').find('tr:last th'));
                    });
                }
            } else if (!noError) {
                notice.on(typeof rs.msg !== 'undefined' ? rs.msg : '加载数据异常', 'danger', {
                    icon: true,
                    title: typeof rs.msg !== 'undefined' ? '加载数据异常' : ''
                });
            }
        });

    };

    Table.prototype.actionRun = function (url, callback) {
        url += (url.indexOf("?") > 0 ? "&" : "?");
        url += 'jsoncallback=?';
        $.getJSON(url, function (rs) {
            if (rs.status) {
                callback();
            } else {
                notice.on(rs.msg ? rs.msg : '操作处理异常', 'danger');
            }
        });
    };

    Table.prototype.loadHeader = function (header) {
        if (!this.config[this.id].headerUrl) {
            return false;
        }
        var url = this.config[this.id].headerUrl, _this = this;
        url += (url.indexOf("?") > 0 ? "&" : "?");
        url += 'jsoncallback=?';
        $.ajax({
            url: url,
            success: function (data) {
                if (data.status) {
                    _this.headerContentAdv(header, data.data);
                }
            },
            dataType: "jsonp",
            async: false
        });
    };

    /**
     * 升级版初始化表头
     * 测试ok后替换老的
     */
    Table.prototype.headerContentAdv = function (header, data) {
        var maxLevel = 0;
        data = fixLevel(data, 0);
        putContent(data);

        function fixLevel(data, level) {
            for (var i in data) {
                data[i]['level'] = level;
                if (data[i]['children'] && data[i]['children'].length > 0) {
                    data[i]['children'] = fixLevel(data[i]['children'], level + 1);
                    if (level >= maxLevel) {
                        maxLevel = level + 1;
                    }
                }
            }
            return data;
        }

        function putContent(data) {
            var tr, _class;
            for (var i in data) {
                tr = header.find('tr[data-level="' + data[i].level + '"]');
                if (tr.length <= 0) {
                    header.append('<tr data-level="' + data[i].level + '"></tr>');
                    tr = header.find('tr[data-level="' + data[i].level + '"]');
                }
                if (data[i]['children']) {
                    tr.append('<th colspan="' + data[i]['children'].length + '" class="text-center">' + data[i]['text'] + '</th>');
                    putContent(data[i]['children']);
                } else {
                    _class = '';
                    if (data[i]['sortable']) {
                        _class += " sort";
                    }
                    tr.append('<th' + (data[i]['field'] ? ' data-tableField="<{' + data[i]['field'] + '}>"' : '') + ' class="' + _class + '">' + data[i]['text'] + '</th>');
                }
            }
        }
    };

    Table.prototype.readyUrl = function (objId, fatherId, page) {
        var url = this.config[objId].url;
        if (!url) {
            return '';
        }
        url += (url.indexOf("?") > 0 ? "&" : "?");
        if (fatherId && /[?&]r_father=\d+/.test(url)) { // 有分页
            url = url.replace(/([?&]r_father=)\d+/, '$1' + fatherId);
        }
        if (!isNaN(this.config[objId].pageNum) && this.config[objId].pageNum > 0) {
            if (!/[?&]page=\d+/.test(url)) {
                url += 'page=1&';
            }
            if (!/[?&]pageNum=\d+/.test(url)) {
                url += 'pageNum=0&';
            }
            url = url.replace(/([?&]page=)\d+/, '$1' + page);
            url = url.replace(/([?&]pageNum=)\d+/, '$1' + this.config[objId].pageNum);
        }

        var relay = this.getRelay(url), _o, val;
        for (var i in relay) {
            _o = $('input[name="' + relay[i] + '"], select[name="' + relay[i] + '"]').first();
            val = _o.attr('type') === 'checkbox' ? (_o.prop("checked") ? _o.val() : '') : _o.val();
            url = url.replace('<{' + relay[i] + '}>', encodeURIComponent(val));
        }
        url += 'jsoncallback=?';
        return url;
    };

    Table.prototype.getRelay = function (url) {
        //把url中所有<{}>找出来
        if (!url) {
            return [];
        }
        url = url.match(/<\{([^}]+)\}>/ig);
        for (var i in url) {
            url[i] = url[i].substr(2, url[i].length - 4);
        }
        return url ? url : [];
    };

    Table.prototype.loadData = function (obj, page) {
        var id = obj.attr('id'), url = this.readyUrl(id, 0, page);
        if (!url) {
            notice.on('<code>data-url</code>没有配置', 'danger', {icon: true});
            return false;
        }
        var loadingId = loading.on(obj), _this = this, isObj = this.config[id].isObj,
            noError = this.config[id].noError;
        $.ajax({
            dataType: "jsonp", async: false,
            url: url, success: function (rs) {
                loading.off(loadingId);
                if (rs.status) {
                    if (rs.data.length <= 0) {
                        if (!noError) {
                            notice.on('没有数据', 'warning', {icon: true});
                        }
                    } else if (isObj) {
                        _this.bodyObject(obj, rs.data);
                    } else {
                        _this.headerContent(obj, rs.data, rs.header);
                        _this.bodyContent(obj, rs.data, page);
                        if (page === 1 && obj.attr('data-pageNum')) {
                            if (!rs.pages) {
                                rs.nums = rs.data.length || Object.keys(rs.data).length;
                                rs.pages = Math.ceil(rs.nums / obj.attr('data-pageNum'));
                            }
                            _this.initPage(obj, rs.pages, rs.nums);
                        }
                    }
                    _this.callback(obj);
                } else {
                    obj.find('tbody').empty();
                    if (!noError) {
                        if (typeof rs.msg !== 'undefined') {
                            notice.on(rs.msg, 'danger', {icon: true, title: '加载数据异常'});
                        } else {
                            notice.on('没有数据', 'warning', {icon: true});
                        }
                    }
                }
            },
            error: function () {
                loading.off(loadingId);
            }
        });
    };

    Table.prototype.initPage = function (obj, page, rsNum) {
        var pageNum = parseInt(obj.attr('data-pageNum'));
        this.pages = pageNum;
        obj.find('tfoot #tablePage').remove();
        obj.find('tfoot').append('<tr id="tablePage"><td colspan="' + obj.find('thead tr:last th').length + '"><ul class="pagination pagination-sm pull-right" style="margin: 0;"></ul></td></tr>');
        obj.find('tfoot #tablePage .pagination').append('<li data-page="' + 1 + '"><a href="#">' + 1 + '</a></li>');
        obj.find('tfoot #tablePage .pagination').append('<li style="display:none" class="ellipsis disabled"><a href="#">...</a></li>');
        obj.find('tfoot #tablePage .pagination').append('<li style="display:none" class="ellipsis disabled"><a href="#">...</a></li>');
        if (page > 1) obj.find('tfoot #tablePage .pagination').append('<li data-page="' + page + '"><a href="#">' + page + '</a></li>');
        if (rsNum) {
            obj.find('tfoot #tablePage .pagination').append('<li class="disabled"><span>共 ' + rsNum + '条</span></li>');
        }

        this.selectPage(obj, localStorage['page_' + window.location.pathname + '_' + obj.attr('id')]);
    };

    Table.prototype.selectPage = function (obj, page) {
        //var pageNum = parseInt(obj.attr('data-pageNum'));
        if (!page || isNaN(page)) {
            page = 1;
        }
        page = parseInt(page);
        obj.find('tbody tr').hide();
        if (obj.find('tbody tr[data-page="' + page + '"]').length <= 0) {
            this.loadData(obj, page);
        } else {
            obj.find('tbody tr[data-page="' + page + '"]').show();
        }

        obj.find('tfoot .pagination li.active').removeClass('active');
        obj.find('tfoot .pagination li[data-page]._add').remove();
        var max = parseInt(obj.find('tfoot .pagination li[data-page]:last').text());
        for (var x = page + 3; x >= page - 4; x--) {
            if (x <= 1 || x >= max) {
                continue;
            }
            obj.find('tfoot .pagination li.ellipsis:first').after('<li data-page="' + x + '" class="_add"><a href="#">' + x + '</a></li>');
        }
        if (page > 6) {
            obj.find('tfoot .pagination li.ellipsis:first').show();
        } else {
            obj.find('tfoot .pagination li.ellipsis:first').hide();
        }
        if (page < max - 3) {
            obj.find('tfoot .pagination li.ellipsis:last').show();
        } else {
            obj.find('tfoot .pagination li.ellipsis:last').hide();
        }
        obj.find('tfoot .pagination li[data-page="' + page + '"]').addClass('active');
    };

    Table.prototype.headerContent = function (tableObj, data, header) {
        var headerObj = tableObj.children('thead');
        if (headerObj.find('tr th').length > 0 || tableObj.attr('data-headerUrl')) {
            return false;
        }
        headerObj.append('<tr></tr>');
        var tr = headerObj.children('tr:last'), field = [], exist = {};
        if (header) {
            $.each(header, function (i, h) {
                var style = '';
                if (h.style) {
                    for (var x in h.style) {
                        style += x + ':' + h.style[x] + ';';
                    }
                }
                tr.append('<th data-tableField="<{' + h.key + '}>"' + (style.length > 0 ? ' style="' + style + '"' : "") + '>' + h.txt + '</th>');
            });
        } else {
            $.each(data, function (_k, v) {
                if (typeof v === 'string') {
                    field.push('<{this}>');
                    headerObj.hide();
                    return false;
                } else {
                    for (var k in v) {
                        if (k[0] !== '_' && typeof exist['e_' + k] === 'undefined') {
                            exist['e_' + k] = 1;
                            field.push('<{' + k + '}>');
                        }
                    }
                }
            });
            for (var i in field) {
                tr.append('<th data-tableField="' + field[i] + '">' + field[i].substr(2, field[i].length - 4) + '</th>');
            }
        }
        return true;
    };

    Table.prototype.bodyContent = function (tableObj, dataArray, page) {
        var headerTh = tableObj.children('thead').find('tr:last th'), body = tableObj.children('tbody');
        var pageNum = tableObj.attr('data-pageNum');
        body.empty();
        var _this = this, i = 0;
        $.each(dataArray, function (dataI, data) {
            var rowId = page + '-' + dataI;
            if (pageNum && page === 1) {
                rowId = (Math.floor(i / pageNum) + 1) + '-' + dataI;
            }
            _this.putRow(body, rowId, data, headerTh);
            i++;
        });
        this.autoExtend(body, this.history());
    };

    Table.prototype.autoExtend = function (body, history) {
        var row = '', tr = null;
        for (var i in history) {
            row = row ? (row + '~' + history[i]) : history[i];
            tr = body.find('tr[data-row="' + row + '"]');
            if (tr.length > 0 && tr.find('td:first span._table-plus').length > 0) {
                tr.find('td:first span._table-plus').click();
            }
        }
        if (i < history.length) {
            var _this = this;
            setTimeout(function () {
                _this.autoExtend(body, history);
            }, 200);
        }
    };

    Table.prototype.history = function (id) {
        if (id === undefined) {
            var history = localStorage["data_list_extend_" + window.location.pathname];
            if (history) {
                return history.split('~');
            } else {
                return [];
            }
        } else {
            localStorage["data_list_extend_" + window.location.pathname] = id;
        }
    };

    Table.prototype.bodyObject = function (tableObj, dataArray) {
        var body = tableObj.children('tbody'), objId = tableObj.attr('id');
        body.empty();

        var row = 0, config = this.config[objId];
        data2row(null, dataArray, 0);

        function data2row(k, data, level) {
            if (typeof data === 'object') {
                if (k) {
                    row++;
                    body.append('<tr' + (config.maxRow && row > config.maxRow ? " style='display:none'" : "") + '><th colspan="2" style="padding-left: ' + level * 10 + 'px">' + k + '</th></tr>');
                }
                for (var i in data) {
                    data2row(i, data[i], level + 1);
                }
            } else {
                row++;
                body.append('<tr' + (config.maxRow && row > config.maxRow ? " style='display:none'" : "") + '><th style="padding-left: ' + level * 10 + 'px">' + k + '</th><td>' + data + '</td></tr>');
            }
        }

        if (config.maxRow && row > config.maxRow) {
            body.append('<tr class="moreRow"><td colspan="2"><span class="ti-angle-double-down"></span> 更多</td></tr>');
        }
    };

    Table.prototype.putRow = function (obj, rowId, data, headerTh) {
        var tr = null, _this = this, padding = 0;
        if (obj.prop('tagName') === 'TBODY') {
            obj.append('<tr data-row="' + rowId + '" data-page="' + rowId.split('-')[0] + '"></tr>');
            tr = obj.children('tr[data-row="' + rowId + '"]');
        } else {
            padding = parseInt(obj.find('td:first').css('padding-left')) + 20;
            var fatherObj = obj.next('tr[data-father="' + obj.attr('data-row') + '"]:last');
            if (fatherObj.length <= 0) {
                fatherObj = obj;
            }
            fatherObj.after('<tr data-row="' + rowId + '" data-father="' + obj.attr('data-row') + '"></tr>');
            tr = fatherObj.next('tr[data-row="' + rowId + '"]');
        }
        if (typeof data === 'string') {
            data = {this: data};
        }
        $.each(headerTh, function () {
            tr.append('<td></td>');
            var model = $(this).attr('data-tableField'), dataIf = $(this).attr('data-if'),
                dataElse = $(this).attr('data-else');
            if (model) {
                var val = null;
                if (dataIf) {
                    var ifCmd = module.value_format(dataIf, data), ifRs = false;
                    try {
                        ifRs = eval(ifCmd);
                    } catch (e) {
                    }
                    if (ifRs) {
                        val = module.value_format(model, data);
                        val = _this.replaceValue($(this), val);
                    } else if (dataElse) {
                        val = module.value_format(dataElse, data);
                        val = _this.replaceValue($(this), val);
                    }
                } else {
                    val = module.value_format(model, data);
                    val = _this.replaceValue($(this), val);
                }
                if (val) {
                    tr.children('td:last').html(val);
                }
            }
        });
        if (padding > 0) {
            tr.find('td:first').css('padding-left', padding);
        }
        if (data._son && data._son > 0) {
            tr.find('td:first').prepend('<span class="fa fa-plus-square-o _table-plus" data-fid="' + data._fid + '"></span> ');
        }
    };

    Table.prototype.replaceG = [];
    Table.prototype.replaceValue = function (tr, value) {
        var id = tr.attr('data-replace');
        if (typeof  id === 'undefined') {
            return value;
        }
        var data = {};
        if (isNaN(id)) {
            id = id.split(';');
            for (var i in id) {
                id[i] = id[i].split(',');
                data[id[i][0]] = id[i][1];
            }
            this.replaceG.push(data);
            tr.attr('data-replace', this.replaceG.length - 1);
        } else {
            data = this.replaceG[id];
        }
        return typeof data[value] === 'undefined' ? value : data[value];
    };

    /**
     * 两种callback模式 一个是data-callback
     * 另外一个是定义window.__callback
     * @param obj
     */
    Table.prototype.callback = function (obj) {
        if (obj.attr('data-callback')) {
            Init.funcCallback(obj.attr('data-callback'))
        }
        if (window.__callback && window.__callback['data-table'] && window.__callback['data-table'][obj.attr('id')]) {
            $.each(window.__callback['data-table'][obj.attr('id')], function (i, callback) {
                callback(obj);
            });
        }
    };

    Table.prototype.initCss = function () {
        if (window.__table_list_css) {
            return false;
        }
        window.__table_list_css = true;
        $('head').append("<style>" +
            ".tableButton{" +
            "   position: absolute; right: -1px; top:-21px;" +
            "   display: none" +
            "}" +
            ".table:hover .tableButton{" +
            "   display: block;" +
            "}" +
            ".table tbody tr td:last-child:not(:first-child){" +
            "   text-align:right" +
            "}" +
            ".table tbody ._table-plus,.table tbody ._table-minus{" +
            "   cursor: pointer" +
            "}" +
            ".table tr.no-data{" +
            "   height: 80px;" +
            "}" +
            ".table tr.moreRow{" +
            "   cursor:pointer;" +
            "}" +
            ".table tr.moreRow td{" +
            "   text-align: center!important;" +
            "}" +
            "table thead th.sort{" +
            "   cursor: pointer;" +
            "}" +
            "table thead th.sort:after{" +
            "   content: '\\f0dc';" +
            "   font: normal normal normal 14px/1 FontAwesome;" +
            "   padding-left: 5px;" +
            "   color: #CCCCCC;" +
            "}" +
            "table thead th.sort-up:after{" +
            "   content: '\\f0de';" +
            "   color: inherit;" +
            "}" +
            "table thead th.sort-down:after{" +
            "   content: '\\f0dd';" +
            "   color: inherit;" +
            "}" +
            "</style>");
    }
});